home *** CD-ROM | disk | FTP | other *** search
-
- BEGINNER'S FORTH TUTORIAL
-
- by Phil Burk
-
-
- Purpose
- -------
-
- The intent of this tutorial is to provide a series of
- experiments that will introduce you to the major concepts of
- Forth. It is only a starting point. Feel free to deviate
- from the sequences I provide. A free form investigation
- that is based on your curiosity is probably the best way to
- learn any language and Forth is especially well adapted to
- this type of learning. There are a number of excellent
- text books on Forth that you may want to use along with this
- tutorial.
-
- While following the tutorial, when you see ENTER: you should
- type in the next set of statements right into the JForth
- window. You can enter them in upper or lower case. At the
- end of each line, press the RETURN (or ENTER) key; this
- causes JForth to interpret what you've entered. However, if
- you don't see ENTER:, then don't type anything in.
-
- Note that statements between parenthesis, ( like this ) OR
- following a backslash, \ like this, do NOT have to be typed
- in, as they are Forth-style comments provided for clarity.
-
- This Tutorial is divided into the following sections:
-
- Purpose
- Forth Syntax
- The Stack
- Arithmetic Operations
- Defining a New Word
- More Arithmetic
- Arithmetic Overflow
- Converting Algebraic Expressions to Forth
- Character Input and Output
- Using the Precompiled Amiga Data Structures and Function Calls
- Opening and Closing Libraries
-
- Several problems are presented in this tutorial; the answers
- may be found at the end.
-
-
- Forth Syntax
- ------------
-
- Forth has one of the simplest syntaxes, or formats, of any
- computer language. The syntax can be stated as follows,
- "Forth code is a bunch of words with spaces between them."
- This is even simpler than English!
-
- Each word is equivalent to a function or subroutine in a
- language like 'C'. They are executed in the order they
- appear in the code. The following statement, for example,
- could appear in a Forth program:
-
- WAKE.UP EAT.BREAKFAST WORK EAT.DINNER PLAY SLEEP
-
- Forth word names can have any combination of letters,
- numbers, or punctuation. We will encounter words with names
- like:
-
- ." #S SWAP MOVE ! @ . *
-
- They are all called words. The word $%%-GL7OP is a legal
- Forth name, although not a very good one. It is up to the
- programmer to name words in a sensible manner.
-
-
- The Stack
- ---------
-
- The Forth language is based on the concept of a stack.
- Imagine a stack of blocks with numbers on them. You can add
- or remove numbers from the top of the stack. You can also
- rearrange the order of the numbers. Forth uses several
- stacks. The Parameter Stack is the one used for passing
- data between Forth words so we will concentrate our
- attention there. The Parameter Stack is also known as the
- Data Stack. The Return Stack is another Forth stack that is
- primarily for internal system use. In this tutorial, when
- we refer to the "stack," we will be referring to the
- Parameter Stack. The stack is initially empty. To put some
- numbers on the stack, ENTER:
-
- 23 7 9182
-
- You will notice that the 'ok' message now has a '3' in front
- of it. This tells you that there are three numbers on the
- stack.
-
- Let's now print the number on top of the stack using the
- Forth word '.' which is pronounced "dot". This is a hard
- word to write about in a text-based tutorial because it is a
- single period. ENTER:
-
- .
-
- You should see the last number you entered, 9,182 ,
- printed. Forth has a very handy word for showing you what's
- on the stack. It is .S, which is pronounced "dot S". The
- name was constructed from "dot" for print, and "S" for
- stack. If you enter:
-
- .S
-
- you will see your numbers in a list. The number at the far
- right is the one on top of the stack.
-
- You will notice that the 9182 is not on the stack. The word
- '.' removes the number on top of the stack before printing
- it. In contrast, '.S' leaves the stack untouched.
-
- We have a way of documenting the effect of words on the
- stack with a stack diagram. A stack diagram is contained in
- parentheses. In Forth, the parentheses indicate a comment.
- In the examples that follow, you do not need to type in the
- comments. When you are programming, of course, we encourage
- the use of comments and stack diagrams to make your code
- more readable. In Forth, we often use stack diagrams to
- illustrate the state of the stack. Do not type these in.
- The stack diagram for a word like '.' would be:
-
- . ( N -- , print number on top of stack )
-
- The symbols to the left of -- describe the parameters that a
- word expects to process. In this example, N stands for any
- integer number. To the right of --, up to the comma, is a
- description of the stack parameters when the word is
- finished, in this case there are none because 'dot' "eats"
- the N that was passed in. (Note that the stack descriptions
- are not necessary, but they are a great help when learning
- other peoples programs.)
-
- The text following the comma is an English description of
- the word. You will note that after the --, N is gone. You
- may be concerned about the fact that there were other
- numbers on the stack, namely 23 and 7 . The stack diagram,
- however, only describes the portion of the stack that is
- affected by the word.
-
- Between examples, you will probably want to clear the stack.
- If you enter 0SP, pronounced "zero S P", then the stack will
- be cleared. Since the stack is central to Forth, it is
- important to be able to alter the stack easily. Let's look
- at some more words that manipulate the stack. ENTER:
-
- 0SP .S \ That's a 'zero' 0, not an 'oh' O.
- 777 DUP .S
-
- You will notice that there are two copies of 777 on the
- stack. The word DUP duplicates the top item on the stack.
- This is useful when you want to use the number on top of the
- stack and still have a copy. The stack diagram for DUP
- would be:
-
- DUP ( n -- n n , DUPlicate top of stack )
-
- Another useful word, is SWAP. ENTER:
-
- 0SP 23 7 .S
- SWAP .S
- SWAP .S
-
- The stack diagram for SWAP would be:
-
- SWAP ( a b -- b a , swap top two items on stack )
-
- Now ENTER:
-
- OVER .S
- OVER .S
-
- The word OVER causes a copy of the second item on the stack
- to leapfrog over the first. its stack diagram would be:
-
- OVER ( a b -- a b a , copy second item on stack )
-
- Here is another commonly used Forth word:
-
- DROP ( a -- , remove item from the stack )
-
- Can you guess what we will see if we ENTER:
-
- 0SP 11 22 .S
- DROP .S
-
- Another handy word for manipulating the stack is ROT.
- ENTER:
-
- 0SP 11 22 33 44 .S
- ROT .S
-
- The stack diagram for ROT is, therefore:
-
- ROT ( a b c -- b c a , ROTate third item to top )
-
- You have now learned the more important stack manipulation
- words. You will see these in almost every Forth program. I
- should caution you that if you see too many stack
- manipulation words being used in your code then you may want
- to reexamine and perhaps reorganize your code. You will
- often find that you can avoid excessive stack manipulations
- by using local or global VARIABLES which will be discussed
- later. If you want to grab any arbitrary item on the stack,
- use PICK . ENTER:
-
- 0SP
- 14 13 12 11 10
- 3 PICK . ( prints 13 )
- 0 PICK . ( prints 10 )
- 4 PICK .
-
- PICK makes a copy of the Nth item on the stack. The
- numbering starts with zero, therefore:
-
- 0 PICK is equivalent to DUP
- 1 PICK is equivalent to OVER
-
- PICK ( ... v3 v2 v1 v0 N -- ... v3 v2 v1 v0 vN )
-
- (Warning. The Forth-79 and FIG Forth standards differ from
- the Forth '83 standard in that their PICK numbering starts
- with one, not zero.)
-
- I have included the stack diagrams for some other useful
- stack manipulation words. Try experimenting with them by
- putting numbers on the stack and calling them to get a feel
- for what they do. Again, the text in parentheses is just a
- comment and need not be entered.
-
- DROP ( n -- , remove top of stack )
- ?DUP ( n -- n n | 0 , duplicate only if non-zero, '|' means OR )
- -ROT ( a b c -- c a b , rotate top to third position )
- 2SWAP ( a b c d -- c d a b , swap pairs )
- 2OVER ( a b c d -- a b c d a b , leapfrog pair )
- 2DUP ( a b -- a b a b , duplicate pair )
- 2DROP ( a b -- , remove pair )
- NIP ( a b -- b , remove second item from stack )
- TUCK ( a b -- b a b , copy top item to third position )
-
- Problems:
-
- Start each problem by entering:
-
- 0SP 11 22 33
-
- Then use the stack manipulation words you have learned to
- end up with the following numbers on the stack:
-
- 1) 11 33 22 22
-
- 2) 22 33
-
- 3) 22 33 11 11 22
-
- 4) 11 33 22 33 11
-
- 5) 33 11 22 11 22
-
- Answers to the problems can be found at the end of this
- tutorial.
-
-
- Arithmetic Operations
- ---------------------
-
- Great joy can be derived from simply moving numbers around
- on a stack. Eventually, however, you'll want to do something
- useful with them. This section describes how to perform
- arithmetic operations in Forth.
-
- The Forth arithmetic operators work on the numbers currently
- on top of the stack. If you want to add the top two numbers
- together, use the Forth word + pronounced "plus". ENTER:
-
- 2 3 + .
- 2 3 + 10 + .
-
- This style of expressing arithmetic operations is called
- Reverse Polish Notation, or RPN. It will already be
- familiar to those of you with HP calculators. In the
- following examples, I have put the algebraic equivalent
- representation in a comment.
-
- Some other arithmetic operators are - * / . ENTER:
-
- 30 5 - . \ 25=30-5
- 30 5 / . \ 6=30/5
- 30 5 * . \ 150=30*5
- 30 5 + 7 / . \ 5=(30+5)/7
-
- Some combinations of operations are very common and have
- been coded in assembly language for speed. For example, 2*
- is short for 2 * . You should use these whenever possible
- to increase the speed of your program. These include:
-
- 1+ 1- 2+ 2- 2* 2/
-
- Try entering:
-
- 10 1- .
- 7 2* 1+ . ( 15=7*2+1 )
-
- One thing that you should be aware of is that when you are
- doing division with integers using /, the remainder is lost.
- ENTER:
-
- 15 5 / .
- 17 5 / .
-
- This is true in all languages on all computers. Later we
- will examine /MOD and MOD which do give the remainder.
-
-
- Defining a New Word
- -------------------
-
- It's now time to write a small program in Forth. You can do
- this by defining a new word that is a combination of words
- we have already learned. Let's define and test a new word
- that takes the average of two numbers.
-
- We will make use of two new words, : ( "colon"), and ; (
- "semicolon") . These words start and end a typical Forth
- definition. When you type this in, you may want to time how
- long it takes between hitting the RETURN key and the
- appearance of the OK prompt. This will be how long it takes
- Forth to compile and link this small program. ENTER:
-
- : AVERAGE ( a b -- avg ) + 2/ ;
-
- Congratulations. You have just written a Forth program. If
- you are used to 'C', you were probably wondering what to get
- from the kitchen while compiling. One danger of programming
- in Forth is that, once hooked, you may never take time to
- eat.
-
- Let's look more closely at what just happened. The colon
- told Forth to add a new word to its list of words. This
- list is called the Forth dictionary. The name of the new
- word will be whatever name follows the colon. Any Forth
- words entered after this will be compiled into the new word.
- This continues until the semicolon is reached which finishes
- the definition.
-
- Let's test this word, ENTER:
-
- 10 20 AVERAGE . ( should print 15 )
-
- If you wish, you can easily view the assembly code that the
- JForth compiler created for AVERAGE (note that you do NOT
- have to understand assembly-language to program in JForth.
- However, if you do, you will appreciate JForth's extensive
- Motorola-format support, both in assembly and disassembly.)
- ENTER:
-
- DEF AVERAGE
-
- Once a word has been defined, it can be used to define more
- words. Let's write a word that tests our word AVERAGE.
- ENTER:
-
- : TEST ( --) 50 60 AVERAGE . ;
- TEST
-
- Try combining some of the words you have learned into new
- Forth definitions of your choice. If you promise not to be
- overwhelmed, you can get a list of the words that are
- available for programming if you ENTER:
-
- WORDS
-
- You can stop this listing by hitting the SPACE BAR. To
- continue, hit the RETURN key. To stop, ENTER:
-
- QUIT
-
- Don't worry, only a small fraction of these will be used
- directly in your programs, so you will never have to learn
- them all. (Because we've pre-compiled so much in this demo
- (ARexx, EZGraphics interface, debugger, etc.), there is an
- 'abundance of words' in this dictionary, to put it mildly!)
-
-
- More Arithmetic
- ---------------
-
- When you need to know the remainder of a divide operation,
- /MOD will return the remainder as well as the quotient. the
- word MOD will only return the remainder. ENTER:
-
- 0SP
- 53 10 /MOD .S
- 0SP
- 7 5 MOD .S
-
- Two other handy words are MIN and MAX . They accept two
- numbers and return the MINimum or MAXimum value
- respectively. ENTER:
-
- 56 34 MAX .
- 56 34 MIN .
- -17 0 MIN .
-
- Some other useful words are:
-
- ABS ( n -- abs(n) , absolute value of n )
- NEGATE ( n -- -n , negate value, faster then -1 * )
- ASHIFT ( n c -- n*(2**c) , arithmetic shift of n )
- SHIFT ( n c -- n' , logical shift of n )
-
- ASHIFT can be used if you have to multiply quickly by a
- power of 2 . A negative count is like doing a divide. This
- is much faster than doing a regular multiply and should be
- used whenever possible. ENTER:
-
- : 256* 8 ASHIFT ;
- 3 256* .
-
-
- Arithmetic Overflow
- -------------------
-
- If you are having problems with your calculation overflowing
- the 32-bit precision of the stack, then you can use */ .
- This produces an intermediate result that is 64 bits long.
- Try the following three methods of doing the same
- calculation. Only the one using */ will yield the correct
- answer, 5197799.
-
- 34867312 99154 * 665134 / .
- 34867312 665134 / 99154 * .
- 34867312 99154 665134 */ .
-
-
- Converting Algebraic Expressions to Forth
- -----------------------------------------
-
- How do we express complex algebraic expressions in Forth?
- For example: 20 + (3 * 4)
-
- To convert this to Forth you must order the operations in
- the order of evaluation. In Forth, therefore, this would
- look like:
-
- 3 4 * 20 +
-
- Evaluation proceeds from left to right in Forth so there is
- no ambiguity. Compare the following algebraic expressions
- and their Forth equivalents: (Do not enter these!)
-
- (100+50)/2 ==> 100 50 + 2/
- ((2*7) + (13*5)) ==> 2 7 * 13 5 * +
-
- If any of these expressions puzzle you, try entering them
- one word at a time, while viewing the stack with .S (dot-S).
-
- Problems:
-
- Convert the following algebraic expressions to their
- equivalent Forth expressions. (Do not enter these because
- they are not Forth code!)
-
- (12 * ( 20 - 17 ))
- (1 - ( 4 * (-18) / 6) )
- ( 6 * 13 ) - ( 4 * 2 * 7 )
-
- Use the words you have learned to write these new words:
-
- SQUARE ( N -- N*N , calculate square )
- DIFF.SQUARES ( A B -- A*A-B*B , difference of squares )
- AVERAGE4 ( A B C D -- [A+B+C+D]/4 )
- HMS>SECONDS ( HOURS MINUTES SECONDS -- TOTAL-SECONDS , convert )
-
-
- Character Input and Output
- --------------------------
-
- The numbers on top of the stack can represent anything. The
- top number might be how many blue whales are left on Earth
- or your weight in kilograms. It can also be an ASCII
- character. ENTER:
-
- 72 EMIT 105 EMIT
-
- You should see the word "Hi" appear before the OK. The 72
- is an ASCII 'H' and 105 is an 'i'. EMIT takes the number on
- the stack and outputs it as a character. If you want to
- find the ASCII value for any character, you can use the word
- ASCII . ENTER:
-
- ASCII W .
- ASCII % DUP . EMIT
- ASCII A DUP .
- 32 + EMIT
-
- Notice that the word ASCII is a bit unusual because its
- input comes not from the stack, but from the following text.
- In a stack diagram, we represent that by putting the input
- in angle brackets, <input>. Here is the stack diagram for
- ASCII.
-
- ASCII ( <char> -- char , get ASCII value of a character )
-
- Using EMIT to output character strings would be very
- tedious. Luckily there is a better way. ENTER:
-
- : TOFU ." Yummy bean curd!" ;
-
- TOFU
-
- The word ." , pronounced "dot quote", will take everything
- up to the next quotation mark and print it to the screen.
- Make sure you leave a space after the first quotation mark.
- When you want to have text begin on a new line, you can
- issue a carriage return using the word CR . ENTER:
-
- : SPROUTS ." Miniature vegetables." ;
- : MENU
- CR TOFU CR SPROUTS CR
- ;
- MENU
-
- You can emit a blank space with SPACE . A number of spaces
- can be output with SPACES . ENTER:
-
- CR TOFU SPROUTS
- CR TOFU SPACE SPROUTS
- CR 10 SPACES TOFU CR 20 SPACES SPROUTS
-
- For character input, Forth uses the word KEY which
- corresponds to the word EMIT for output. KEY waits for the
- user to press a key then leaves its value on the stack.
- ENTER:
-
- : TESTKEY ( -- )
- ." Hit a key: " KEY CR
- ." That = " . CR
- ;
- TESTKEY
-
- The following is a summary of some useful Input/Out words...
-
- EMIT ( char -- , output character )
- KEY ( -- char , input character )
- SPACE ( -- , output a space )
- SPACES ( n -- , output n spaces )
- ASCII ( <char> -- char , convert to ASCII )
- CR ( -- , start new line , carriage return )
- ." ( -- , output " delimited text )
-
-
- Using the Precompiled Amiga Data Structures and Function Calls
- --------------------------------------------------------------
-
- A significant portion of the complete Amiga interface
- offered in the normal JForth release has been pre-compiled
- for you in this demo version. To call an Amiga library
- function, it is usually only necessary to know the name of
- that function and possibly pass it the name of an Amiga data
- structure (such as a Window or Gadget structure).
-
- As an example, let's assume you have stored the
- JForth-relative address of an Amiga 'Window' structure in a
- variable called MY-WINDOW. If the window was open, you
- could close it with a statement like:
-
- MY-WINDOW @ CLOSEWINDOW()
-
- JForth uses descriptive function names that are identical
- with those defined by Commodore, and adds the () as a visual
- cue that this routine is a direct call to the Amiga library
- system. Examples of other provided calls include
- OPENWINDOW(). ISREXXMSG(). CREATESTDIO(), etc. A complete
- list can be obtained by typing in:
-
- WORDS-LIKE ()
-
- JForth also provides the ability to define and access all
- the standard Amiga structures. Many have been pre-compiled
- in the demo. The syntax of a JForth structure reference is:
-
- <structure> <operator> <element>
-
- The three available operators are:
-
- S@ \ fetch element contents
- S! \ store element contents
- .. \ return address (relative) of element
-
- For example, to read the above window's height...
-
- MY-WINDOW @ s@ wd_Height ( -- height )
-
- ...to set the same element to 120...
-
- 120 MY-WINDOW @ s! wd_Height
-
- ...to get the JForth-relative address of that element...
-
- MY-WINDOW @ .. wd_Height ( -- address )
-
- Note that the structure names are exactly the same as those
- documented in the ROM KERNEL MANUAL, and the the element
- names are the same as that used in the Amiga's assembler
- files.
-
-
- Opening and Closing Libraries
- -----------------------------
-
- As is customary with many languages, you must 'open' a
- specific Amiga Library before calling its functions. JForth
- makes this easy by providing a single open-word for each
- standard Amiga library.
-
- All you have to do is to simply state the name of the
- library ending with a '?' character. For example, to open
- the 'graphics.library' facility of the Amiga, just enter:
-
- GRAPHICS?
-
- As another example, assume you want to access functions in
- the 'icon.library', you should, at least once before calling
- one (it doesn't hurt to do it multiple times), state:
-
- ICON?
-
- See? It's very easy. If for some reason the library cannot
- be opened, JForth will issue a descriptive error message and
- abort the running program.
-
- Similarly, if you try to call a function in a library that
- hasn't been opened as above, another error message will
- appear and the running program will stop executing.
-
- JForth provides a similar simple syntax for closing those
- libraries that you've opened; it uses a '-' character BEFORE
- the name. To close the above-opened libraries, use:
-
- -GRAPHICS
- -ICON
-
- Note that if you forget to close libraries, JForth will do so
- automatically when you exit the JForth program (via BYE).
-
-
-
-
- Answers to Problems:
-
- If your answer doesn't exactly match these but it works,
- don't fret. In Forth, there are usually many ways to the
- same thing.
-
- Stack Manipulations:
-
- 1) SWAP DUP
- 2) ROT DROP
- 3) ROT DUP 3 PICK
- 4) SWAP OVER 3 PICK
- 5) -ROT 2DUP
-
- Arithmetic:
-
- (12 * (20 - 17)) ==> 20 17 - 12 *
-
- (1 - (4 * (-18) / 6)) ==> 1 4 -18 * 6 / -
-
- (6 * 13) - (4 * 2 * 7) ==> 6 13 * 4 2 * 7 * -
-
- : SQUARE ( N -- N*N )
- DUP *
- ;
-
- : DIFF.SQUARES ( A B -- A*A-B*B )
- SWAP SQUARE
- SWAP SQUARE -
- ;
-
- : AVERAGE4 ( A B C D -- [A+B+C+D]/4 )
- + + + ( add'em up )
- -2 ashift ( divide by four the fast way, or 4 / )
- ;
-
- : HMS>SECONDS ( HOURS MINUTES SECONDS -- TOTAL-SECONDS )
- -ROT SWAP ( -- seconds minutes hours )
- 60 * + ( -- seconds total-minutes )
- 60 * + ( -- seconds )
- ;
-
-